Writing
applications for the phone will likely involve data of some sort.
Silverlight’s support for data binding makes displaying the data to the
user helps you build your applications in a much more powerful way, but
what is data binding exactly? Data binding is simply a way to take data
from a source (e.g. the value of a property on an object) and show it
in a XAML element. If that XAML element is a control, it also support
pushing changes back to the source of the data. While that is a pretty
simple explanation, the explanation is correct. Data binding is
profoundly simple and because it is simple, it is powerful.
Simple Data Binding
At the most basic level a
binding is a connector to pull data from a data source and put it in an
element’s property. As you can see in Figure 1, a binding is in the middle of the data and the element (Control).
Bindings are defined as a markup extension. For example here is a TextBox bound to the Name property:
<TextBox Text="{Binding Name, Source={StaticResource myData}}" />
The Binding markup
extension first takes a path to the property to be bound to then a
number of optional elements. As you can see in this example, the
binding is pulling from a resource object called myData. When the data binding happens, it takes the source of the data binding and uses the property path (the “Name” in this case) to navigate to the data it needs to put in the TextBox’s
Text. The path to the property must be a public property as it uses
reflection to call the getter of the public property to access the data
from the source.
Having to specify the
source for bindings is relatively rare though. The reason for this is
when the source of an object changes, you would have to change it in a
number of places. For example, this XAML would show a simple editor for
some data:
<StackPanel>
<TextBlock>Name</TextBlock>
<TextBox Text="{Binding Name, Source={StaticResource myData}}" />
<TextBlock>Phone Number</TextBlock>
<TextBox Text="{Binding Phone, Source={StaticResource myData}}" />
<TextBlock>BirthDate</TextBlock>
<TextBox Text="{Binding BirthDay, Source={StaticResource myData}}" />
</StackPanel>
Imagine that if the source
changed, all of the TextBox’s would need to be rebound. Instead data
binding uses a property called DataContext. DataContext simply allows
for the source of data binding to exist along the hierarchy of the
XAML. For example, if the DataContext were set at the StackPanel, all
the controls that attempt data binding inside the StackPanel would get
their data from the DataContext instead of needing specific sources:
<StackPanel DataContext="{StaticResource myData}">
<TextBlock>Name</TextBlock>
<TextBox Text="{Binding Name}" />
<TextBlock>Phone Number</TextBlock>
<TextBox Text="{Binding Phone}" />
<TextBlock>BirthDate</TextBlock>
<TextBox Text="{Binding BirthDay}" />
</StackPanel>
When the bindings pull their
data, they will look for a source and when they don’t have one, they’ll
search for the first non-null data source in the hierarchy. In this
case they will find it at the StackPanel level and use that and the source for the data binding. The search for a DataContext will continue up the hierarchy until it finds a valid DataContext.
This walking of the XAML tree is not limited to the current XAML
document. If the data binding is happening inside a control that is
used on another XAML document, it will continue up through all the
parents until is exhausts the entire object tree.
Data binding supports three modes as seen in Table 1.
Table 1. Data Binding Modes
Type | Description | Example |
---|
OneTime | Pulls data from a Source once. | <TextBox Text=“{Binding Name, Mode=OneTime}” />
|
OneWay | (Default) Pulls data from a Source. As the source’s data changes, can pull those changes into the control. | <TextBox Text=“{Binding Name}” /> |
TwoWay | Pulls data from a Source and pushes changes back to the Source as the data changes (normally on the control losing focus). | <TextBox Text=“{Binding Name, Mode=TwoWay}” />
|
The pushing and pulling of
changes all are performed via reflection so that all binding modes work
with any .NET class. There are no requirements for that class to work
with data binding. The one exception to that is if you want changes to
the source object itself to be reflected in the controls via data
binding. For that to work, your source classes must support a simple
interface called INotifyPropertyChange.
When the source data changes, it notifies the binding that the data has
changes which will cause the binding to re-read the data and change the
data in the control as shown in Figure 2.
DataTemplates
As you saw earlier in this chapter, list controls can show any list that supports IList or IEnumerable, but that’s only part of the story. List controls also support the ability to use DataTemplates to customize the look of individual items in the list. You can use a DataTemplate to specify the ItemTemplate to use arbitrary XAML to define what is contained in a ListBox. For example:
<ListBox ItemsSource="{StaticResource theData}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}" />
<Image Source="{Binding ImageUrl}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
As this ListBox creates its individual items, it will use the DataTemplate as a factory to create the XAML that is contained inside. The DataContext for the created XAML becomes the individual item to be shown in the ListBox so that the data binding inside the DataTemplate just works.